#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
#include <time.h>
#include "ProducerConsumerUtilities.h"
#include "Producer.h"
#define MAX_RAND_NUMBER 9999999

void generateProduct(ProducerConsumerManager_t *producerConsumerMgr, int threadIdx){
	sem_t *mutex = &(producerConsumerMgr->mutex);
	sem_t *full = &(producerConsumerMgr->full);
	sem_t *empty = &(producerConsumerMgr->empty);
	int productGenerated = rand()%MAX_RAND_NUMBER;
	
	//等待有空位。如果缓冲区满了，线程阻塞。若成功empty信号量减1
	semWait(empty);//before accessing buffer
	//请求独占访问缓冲区的权限。如果其他线程持有mutex则在此阻塞
	semWait(mutex);
	
	//临界区开始
	++producerConsumerMgr->remainProducts;
	//放入生产的产品（一个随机数）
	producerConsumerMgr->buffer[producerConsumerMgr->producerOffset] = productGenerated;
	//更新数据
	producerConsumerMgr->producerOffset = (producerConsumerMgr->producerOffset + 1) % producerConsumerMgr->bufferSize;
	//打印生产信息
	printf("producer:%d, generate product:%d\n",threadIdx, productGenerated);
	
	//释放互斥锁，并通知消费者缓冲区新增了一个产品，full信号量加1
	semSignal(mutex);//after accessing buffer
	semSignal(full);
} 

//线程入口函数
void *producerThread(void *arg){
	//获取传递来的ThreadStruct_t
	ThreadStruct_t *curThreadStruct = (ThreadStruct_t *)arg;
	//获取共享管理器
	ProducerConsumerManager_t *producerConsumerMgr =
	curThreadStruct->producerConsumerMgr;
	//初始化随机数种子，让不同生产者产生不同序列
	int threadIdx = curThreadStruct->threadIdx;
	
	srand (time(NULL) ^ pthread_self());
	
	 
	
	while(curThreadStruct->producerConsumerMgr->exit_flag == 0){
		//生产一个产品
		generateProduct(producerConsumerMgr, curThreadStruct->threadIdx);
		//先暂停一段时间模拟生产耗时
		sleep(WAIT_TIME_IN_SECOND);// wait WAIT_TIME_IN_SECOND seconds
	}
	
	if (curThreadStruct->threadIdx == 0)
	{
		//producerConsumerMgr->remainProducts is zero indicates there are consumer threads waiting for product
		while(producerConsumerMgr->remainProducts == 0){
			do{
				//生产单个产品
				generateProduct(producerConsumerMgr, curThreadStruct->threadIdx);
				sleep(1);
			}while(producerConsumerMgr->remainProducts != producerConsumerMgr->bufferSize);
		}
	} 
	return arg;
}
